package com.fin.zw.aiqas.service;

import com.fin.zw.aiqas.entity.*;
import com.fin.zw.aiqas.enums.FormulaType;
import com.fin.zw.aiqas.enums.MatchRange;
import com.fin.zw.aiqas.repository.FormulaInfoRepository;
import com.fin.zw.aiqas.repository.KeywordRepository;
import com.fin.zw.aiqas.repository.TaskInfoRepository;
import com.fin.zw.aiqas.util.BadRequestException;
import com.fin.zw.aiqas.util.FormulaUtil;
import com.google.common.collect.Lists;
import com.querydsl.core.BooleanBuilder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.SetUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 质检结果操作
 */
@Service("calculationResultService")
public class CalculationResultService {

    private final static Logger log = LoggerFactory.getLogger(FormulaService.class);

    @Autowired//任务表操作
    private TaskInfoRepository taskInfoRepository;
    @Autowired//质检点表操作
    private FormulaInfoRepository formulaInfoRepository;
    @Autowired //关键字操作
    private KeywordRepository keywordRepository;


    /**
     * 根据任务ID查询任务下面的规则信息
     *
     * @param taskId     任务ID
     * @param chatRecord 聊天记录
     * @return 规则
     */
    public Set<RuleInfo> getCalculationRuleInfo(Long taskId, String chatRecord) {
        //存储满足条件的规则
        Set<RuleInfo> rules = new HashSet<>();
        if (taskId == null || StringUtils.isEmpty(chatRecord)) {
            log.error("任务ID 或 质检语句 为空!!!");
            return null;
        }
        Set<RuleInfo> ruleSet = getRuleInfosFromTask(taskId);
        if (SetUtils.isEmpty(ruleSet)) return null;
        log.info("遍历所有的规则,获取对应的质检点信息");
        ruleSet.stream()
                //过滤掉状态为停用的规则
                .filter(e -> "START".equals(e.getStates().toString()))
                .forEach(e -> {
                    //获取规则的关系表达式
                    String relation = relationController(e.getRelation());
                    log.info("遍历质检点信息,获取质检点类型并进行操作");
                    Set<FormulaInfo> formulas = e.getFormulaInfos();
                    log.info("存储质检点的命中结果,质检点的Id作为key值,命中为true,未命中为false;");
                    Map<String, Integer> resultMap = new HashMap();
                    //同步过得关键词
                    List<FormulaInfo> keywords = formulas.stream().filter(t -> t.getFormulaType().equals(FormulaType.KEYWORD)).collect(Collectors.toList());
                    for (FormulaInfo info : keywords) {
                        log.info("判断关键字类型的质检点是否命中!!");
                        resultMap.put(info.getId().toString(), assertionKeyWords(info, chatRecord));
                    }
                    try {
                        if (FormulaUtil.jsonToFormula(relation, resultMap) == 1) rules.add(e);
                    } catch (RuntimeException exp) {
                        log.error("规则表达式替换错误!");
                        exp.printStackTrace();
                    }
                });
        return rules;
    }

    /**
     * 1.将表达式中的汉字拆分出来
     * 2.按照字符长度排序
     * 3.根据名称查询质检点Id
     * 4.替换表达式
     *
     * @param relation 表达式
     * @return
     */
    public String relationController(String relation) {
        log.info("开始替换关系表达式.....");
        try {
            List<String> formulaCodes = Arrays.asList(relation.split("\\||&|\\(|\\)"));
            //按照长度排序,先替换长字段,再替换短字段
            formulaCodes.sort((code1, code2) -> Integer.compare(code2.length(), code1.length()));
            //根据编码查询质检点ID
            for (String code : formulaCodes) {
                FormulaInfo formula = formulaInfoRepository.findOne(QFormulaInfo.formulaInfo.formulaCode.eq(code.trim())).orElseThrow(() -> new BadRequestException("", "根据质检点编码没有查到质检点"));
                relation = relation.replace(code, formula.getId().toString());
            }
        } catch (RuntimeException e) {
            log.error("关系表达式处理异常!!!!");
        }
        log.info("替换后的表达式为 :"+relation);
        log.info("关系表达式替换完成!!!");
        return relation;
    }


    /**
     * 根据任务Id查询该任务下的所有规则信息
     *
     * @param taskId 任务Id
     * @return
     */
    public Set<RuleInfo> getRuleInfosFromTask(Long taskId) {
        log.info("根据任务ID查询任务信息!!!");
        Optional<TaskInfo> taskOptional = taskInfoRepository.findById(taskId);
        if (!taskOptional.isPresent()) {
            log.error("根据任务ID查询任务信息为空!!!");
            return null;
        }
        log.info("从任务中获取对应的规则信息!!!");
        Set<RuleInfo> ruleSet = taskOptional.get().getRuleInfoSet();
        if (SetUtils.isEmpty(ruleSet)) {
            log.error("任务名称[" + taskOptional.get().getName() + "]中的规则信息为空!");
            return null;
        }
        return ruleSet;
    }



    /**
     * 判断关键字KeyWord对应的该质检点是否命中
     *
     * @param formula
     * @param chatRecord
     * @return
     */
    public Integer assertionKeyWords(FormulaInfo formula, String chatRecord) {
        log.info("查询该质检点所对应的关键字!!!");
        BooleanBuilder kwBuilder = new BooleanBuilder();
        QKeyword qKeyword = QKeyword.keyword;
        kwBuilder.and(qKeyword.keyword_info_id.eq(formula.getId()));
        ArrayList<Keyword> kwList = Lists.newArrayList(keywordRepository.findAll(kwBuilder));
        int hitFlag = 0;
        List<Keyword> hitList = kwList.stream().filter(e -> chatRecord.contains(e.getName())).collect(Collectors.toList());
        if (formula.getMatchType().equals(MatchRange.SHOW_ANY)) {
            if (hitList.size() > 0) hitFlag = 1;
        } else if (formula.getMatchType().equals(MatchRange.SHOW_ALL)) {
            if (hitList.size() == kwList.size()) hitFlag = 1;
        } else if (formula.getMatchType().equals(MatchRange.NOT_SHOW)) {
            if (hitList.size() == 0) hitFlag = 1;
        }
        //不匹配词质检点才算命中(true) selected
        if ("YES".equals(formula.getSelected())) {
            if (hitFlag == 1) {
                hitFlag = 0;
            } else {
                hitFlag = 1;
            }
        }
        return hitFlag;
    }


}
